package com.gitee.wsl.service.task


import com.gitee.wsl.ext.any.entryNotEq
import com.gitee.wsl.service.task.listener.AbstractTaskListener
import com.gitee.wsl.service.task.listener.TaskListener
import com.gitee.wsl.service.task.scope.TaskScope
import com.gitee.wsl.service.RunAble
import com.gitee.wsl.struct.generator.randomUUID
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow

interface Task<SCOPE: TaskScope,STATUS>: RunAble, TaskListener<SCOPE> {
    fun currentState():STATUS
    fun currentStateFlow(): Flow<Pair<STATUS?, STATUS>>
    fun getTaskTag():String
    fun getTaskScope():SCOPE
}

enum class TaskStatus{
    UNKNOWN,QUEUED,STOPPED,PAUSING,PAUSED,WAIT,RUNNING,FINISHED,FAILED,CANCELLED
}

abstract class SampleTask<SCOPE: TaskScope>: AbstractTask<SCOPE, TaskStatus>(TaskStatus.UNKNOWN){
    override fun pause() {}
}

abstract class AbstractTask<SCOPE: TaskScope,STATUS>(
    val initStatus: STATUS,
    adapter: AbstractTaskListener<SCOPE>?=null
): AbstractTaskListener<SCOPE>(adapter), Task<SCOPE, STATUS>, TaskScope {

    val tag:String = randomUUID()

    private var status: STATUS? = null
    private val statusFlow =
        MutableSharedFlow<Pair<STATUS?, STATUS>>(0, 1, BufferOverflow.DROP_OLDEST)

    init {
        setCurrentStatus(initStatus)
    }

    override fun getTaskScope(): SCOPE {
        return this as SCOPE
    }

    override fun getTaskTag(): String {
        return tag
    }

    open fun isRunning():Boolean = currentState() == TaskStatus.RUNNING

    fun setCurrentStatus(newStatus:STATUS){
        val pair = status to newStatus
        status = newStatus
        statusFlow.tryEmit(pair)
        if(pair.entryNotEq())
            fireWhenStateChange()
    }

    protected fun fireWhenStateChange(){
        val scope=getTaskScope()
        when(currentState()){
            TaskStatus.RUNNING ->fireConnect(scope)
            TaskStatus.FAILED ->fireError(scope)
            TaskStatus.PAUSED ->firePaused(scope)
            TaskStatus.STOPPED ->fireCancel(scope)
            TaskStatus.FINISHED ->fireCompleted(scope)
            else -> {}
        }
    }

    override fun currentState(): STATUS = status!!

    override fun currentStateFlow(): Flow<Pair<STATUS?, STATUS>> = statusFlow

    override fun firePending(scope: SCOPE) {
        pendingFun?.invoke(scope)
    }

    override fun fireConnect(scope: SCOPE) {
        connectFun?.invoke(scope)
    }

    override fun fireProgress(scope: SCOPE) {
        progressFun?.invoke(scope)
    }

    override fun firePaused(scope: SCOPE) {
        pausedFun?.invoke(scope)
    }

    override fun fireError(scope: SCOPE) {
        errorFun?.invoke(scope)
    }

    override fun fireCompleted(scope: SCOPE) {
        completeFun?.invoke(scope)
    }

    override fun fireCancel(scope: SCOPE) {
        cancelFun?.invoke(scope)
    }

    override fun fireDelete(scope: SCOPE) {
        deleteFun?.invoke(scope)
    }

}


